﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using LinFu.IoC.Interfaces;
using LinFu.Reflection;

namespace CoreEx.Database.Query.Expressions
{
    /// <summary>
    ///  Provides a base class for database-specific implementations.
    /// </summary>
    public abstract class DbQueryTranslator : DbExpressionVisitor, IInitialize<IServiceRequestResult>
    {

        private DbCommandBuilder _commandBuilder;
        private DbProviderFactory _providerFactory;
       
        /// <summary>
        /// Translates the <paramref name="dbExpression"/> into a <see cref="DbTranslateResult"/> instance.
        /// </summary>
        /// <param name="dbExpression">The <see cref="DbExpression"/> to translate.</param>
        /// <returns><see cref="DbTranslateResult"/></returns>
        public virtual DbTranslateResult Translate(DbExpression dbExpression)
        {
            var sql = Visit(dbExpression);
            var translateResult = new DbTranslateResult(sql,Parameters);
            return translateResult;
        }

        /// <summary>
        /// Gets the name of the provider that this <see cref="DbQueryTranslator"/> is targeting.
        /// </summary>
        protected string ProviderName { get; private set; }

        /// <summary>
        /// Gets a list of <see cref="IDataParameter"/> instances. 
        /// </summary>
        protected IList<IDataParameter> Parameters { get; private set; }

        /// <summary>
        /// Quotes the <paramref name="unquotedIdentifier"/>.
        /// </summary>
        /// <param name="unquotedIdentifier">The original unquoted identifier.</param>
        /// <returns><see cref="string"/></returns>
        protected virtual string QuoteIdentifier(string unquotedIdentifier)
        {
            return _commandBuilder.QuoteIdentifier(unquotedIdentifier);
        }

        protected virtual void CreateParameter(string name, object value)
        {
            var parameter = _providerFactory.CreateParameter();
            parameter.ParameterName = name;
            parameter.Value = value;
            Parameters.Add(parameter);
        }


        /// <summary>
        /// Initializes this service instance.
        /// </summary>
        /// <param name="source">The <see cref="IServiceRequestResult"/> that represents the result of creating this service instance.</param>
        public virtual void Initialize(IServiceRequestResult source)
        {
            ProviderName = source.ServiceName;
            Parameters = new List<IDataParameter>();
            _providerFactory = DbProviderFactories.GetFactory(ProviderName);
            _commandBuilder = _providerFactory.CreateCommandBuilder();

        }
    }
}
